package chen.web.util;

import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import chen.web.MyContext;
import chen.web.MyContextProvider;
import chen.web.util.jdbc.wrapper.QueryInfo;

/**
 * 计算处理请求的时间. 在request对象中保存一个处理请求开始时间的属性值和QueryInfo对象
 * 此过滤器提供一个初始化参数:showProcessTimeInHeader, 用于在header中存放处理请求的时间.
 * showProcessTimeInHeader的值为on时生效, 默认关闭.
 */
public class Timer implements Filter {

	public static final String Process_Start_Time_Attribute_Name = "Process_Start_Time";
	public static final String Query_Info_Attribute_Name = "QueryInfo";
	private static boolean showProcessTimeInHeader = false;
	public static final String Jdbc_Query_Info_Context_Attribute_Name = "Jdbc_Query_Info";
	
	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse)res;
		
		long startTime = System.nanoTime();
		request.setAttribute(Process_Start_Time_Attribute_Name, startTime);
		
		MyContext context = MyContextProvider.getMyContext();
		context.setAttribute(Process_Start_Time_Attribute_Name, startTime);
		//初始化
		QueryInfo info = new QueryInfo();
		context.setAttribute(Jdbc_Query_Info_Context_Attribute_Name, info);
		
		request.setAttribute(Query_Info_Attribute_Name, info);
		
		if(!showProcessTimeInHeader){
			chain.doFilter(request, response);
			return;
		}
		
		ResponseWrapper wrapper = new ResponseWrapper(response);
		chain.doFilter(request, wrapper);
		//已经使用getOutputStream输出
		if(wrapper.isGetOutputStreamCalled()){
			return;
		}
		char[] charArray = wrapper.getCharArray();
		
		long endTime = System.currentTimeMillis();
		response.setIntHeader("Processing-Time", (int)(endTime - startTime));
		//输出内容
		if(charArray != null && charArray.length != 0){
			response.getWriter().print(charArray);
		}
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
		// TODO Auto-generated method stub
		String value = config.getInitParameter("showProcessTimeInHeader");
		if("on".equalsIgnoreCase(value)){
			showProcessTimeInHeader = true;
		}
	}
	
	private static class ResponseWrapper extends HttpServletResponseWrapper{
		private CharArrayWriter caw = null;
		private PrintWriter writer = null;
		private boolean getOutputStreamCalled = false;
		
		public ResponseWrapper(HttpServletResponse response) {
			super(response);
			// TODO Auto-generated constructor stub
		}
		
		@Override
		public PrintWriter getWriter() throws IOException {
			// TODO Auto-generated method stub
			if(writer == null){
				caw = new CharArrayWriter();
				writer = new PrintWriter(caw);
			}
			return writer;
		}
		
		private char[] getCharArray(){
			if(caw == null){
				return null;
			}
			return caw.toCharArray();
		}

		@Override
		public ServletOutputStream getOutputStream() throws IOException {
			// TODO Auto-generated method stub
			getOutputStreamCalled = true;
			return super.getOutputStream();
		}
		
		public boolean isGetOutputStreamCalled(){
			return getOutputStreamCalled;
		}
	}

}
